/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package io;

import common.DomainException;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import domain.DomainFacade;
import domain.DomainFacadeImpl;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 *
 * @author David
 */
public class XMLReader implements Reader {

    private DomainFacade facade;
    private File file;
    private Document dom;

    public XMLReader() {
        this.facade = DomainFacadeImpl.getInstance();
    }

    @Override
    public void openArchitectureFile(File file) {
        this.file = file;
        this.getDOM();
        this.getArchitectureName();
        this.getArchitectureAuthor();
        this.getLayers();
        this.getAllowedLayers();
    }

    @Override
    public void openStructureFile(File file) {
        this.file = file;
        this.getDOM();
        this.getStructureName();
        this.getStructureAuthor();
        this.getUnits();
    }

    private void getDOM() {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            try {
                this.dom = db.parse(file);
            } catch (SAXException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void getArchitectureName() {
        NodeList names = this.dom.getElementsByTagName("name");

        if (names.getLength() == 1) {
            String value = ((Element) names.item(0)).getAttribute("value");
            try {
                this.facade.setArchitectureName(value);
            } catch (DomainException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void getArchitectureAuthor() {
        NodeList names = this.dom.getElementsByTagName("author");

        if (names.getLength() == 1) {
            String value = ((Element) names.item(0)).getAttribute("value");
            try {
                this.facade.setArchitectureAuthor(value);
            } catch (DomainException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void getStructureName() {
        NodeList names = this.dom.getElementsByTagName("name");

        if (names.getLength() == 1) {
            String value = ((Element) names.item(0)).getAttribute("value");
            try {
                this.facade.setStructureName(value);
            } catch (DomainException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void getStructureAuthor() {
        NodeList names = this.dom.getElementsByTagName("author");

        if (names.getLength() == 1) {
            String value = ((Element) names.item(0)).getAttribute("value");
            try {
                this.facade.setStructureAuthor(value);
            } catch (DomainException ex) {
                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void getLayers() {
        NodeList children = this.dom.getDocumentElement().getChildNodes();

        for (int s = 0; s < children.getLength(); s++) {
            if (children.item(s).getNodeName().equals("layer")) {
                String layerName = children.item(s).getAttributes().getNamedItem("name").getNodeValue();
                String layerNumber = children.item(s).getAttributes().getNamedItem("number").getNodeValue();
                try {
                    this.facade.addLayer(layerName, Integer.parseInt(layerNumber));
                } catch (DomainException ex) {
                    Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private void getUnits() {
        NodeList layers = this.dom.getElementsByTagName("layer");

        if (layers.getLength() > 0) {
            for (int s = 0; s < layers.getLength(); s++) {
                Node layer = layers.item(s);
                NodeList children = layer.getChildNodes();
                if (children.getLength() > 0) {

                    for (int s2 = 0; s2 < children.getLength(); s2++) {
                        Node child = children.item(s2);
                        if (child.getNodeName().equals("package")) {
                            try {
                                this.facade.addUnitToLayer(child.getAttributes().getNamedItem("name").getNodeValue(), "PACKAGE", layer.getAttributes().getNamedItem("name").getNodeValue());
                            } catch (DomainException ex) {
                                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        } else if (child.getNodeName().equals("class")) {
                            try {
                                this.facade.addUnitToLayer(child.getAttributes().getNamedItem("name").getNodeValue(), "UNIT", layer.getAttributes().getNamedItem("name").getNodeValue());
                            } catch (DomainException ex) {
                                Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
                            }

                        }
                    }

                }
            }
        }
    }

    private void getAllowedLayers() {
        NodeList allowedToAccessList = this.dom.getElementsByTagName("allowedToAccess");

        if (allowedToAccessList.getLength() > 0) {
            for (int i = 0; i < allowedToAccessList.getLength(); i++) {
                Node allowedToAccess = allowedToAccessList.item(i);

                String parentLayer = allowedToAccess.getParentNode().getAttributes().getNamedItem("name").getNodeValue();

                NodeList accessLayerList = allowedToAccess.getChildNodes();
                for (int s = 0; s < accessLayerList.getLength(); s++) {
                    Node accessLayer = accessLayerList.item(s);
                    if (accessLayer.getNodeName().equals("accessLayer")) {
                        try {
                            facade.addAllowedLayerToLayer(parentLayer, accessLayer.getAttributes().getNamedItem("name").getNodeValue());
                        } catch (DomainException ex) {
                            Logger.getLogger(XMLReader.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            }
        }
    }
}